package com.biz.primus.ms.payment.service;

import com.biz.primus.base.enums.CommonStatus;
import com.biz.primus.base.exception.BizSilentException;
import com.biz.primus.base.exception.utils.AssertUtils;
import com.biz.primus.common.utils.CopyUtils;
import com.biz.primus.common.vo.SpringPageVO;
import com.biz.primus.model.payment.enums.PaymentExceptionEnum;
import com.biz.primus.model.payment.vo.req.MerchantQueryVo;
import com.biz.primus.model.payment.vo.req.MerchantReqVo;
import com.biz.primus.model.payment.vo.resp.MerchantResVo;
import com.biz.primus.ms.base.service.AbstractBaseService;
import com.biz.primus.ms.base.vo.SpringPageToSpringPageVO;
import com.biz.primus.ms.payment.dao.po.Merchant;
import com.biz.primus.ms.payment.dao.repository.MerchantRepository;
import com.biz.primus.ms.payment.event.NewMerchantEvent;
import javax.transaction.Transactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.event.TransactionalEventListener;

import static com.biz.primus.model.payment.enums.PaymentExceptionEnum.ILLEGAL_PARAMETER;
import static com.biz.primus.model.payment.enums.PaymentExceptionEnum.MERCHANT_NOT_FOUND;
import static java.lang.String.format;

/**
 * Created by defei on 9/25/17.
 */
@Slf4j
@Service
public class MerchantService extends AbstractBaseService {

    private final MerchantRepository merchantRepository;

    @Autowired
    public MerchantService(MerchantRepository merchantRepository) {
        this.merchantRepository = merchantRepository;
    }

    @Transactional
    public MerchantResVo create(MerchantReqVo reqVo) {

        validateParams(reqVo);
        Merchant merchant = new Merchant();
        BeanUtils.copyProperties(reqVo, merchant);
        merchant.setId(idService.getNextId());
        merchant.setStatus(CommonStatus.ENABLE);
        Merchant savedMerchant = merchantRepository.save(merchant);
        return toMerchantResVo(savedMerchant);
    }

    /**
     * 查找商户
     *
     * @param merchantId 商户id
     * @return {@link MerchantResVo}
     * @throws BizSilentException {@link PaymentExceptionEnum#ILLEGAL_PARAMETER} || {@link
     * PaymentExceptionEnum#MERCHANT_NOT_FOUND}
     */
    public MerchantResVo getMerchantInfo(Long merchantId) throws BizSilentException {

        AssertUtils.notNull(merchantId, ILLEGAL_PARAMETER, "Argument reqVo.id null.");

        Merchant merchant = merchantRepository.findOne(merchantId);
        AssertUtils.notNull(merchant, MERCHANT_NOT_FOUND, format("Merchant not found by id:%s", merchantId));

        MerchantResVo merchantResVo = new MerchantResVo();
        BeanUtils.copyProperties(merchant, merchantResVo);
        return merchantResVo;
    }

    /**
     * 查找商户
     *
     * @param merchantId 商户id
     * @return {@link MerchantResVo}
     * @throws BizSilentException {@link PaymentExceptionEnum#ILLEGAL_PARAMETER} || {@link
     * PaymentExceptionEnum#MERCHANT_NOT_FOUND}
     */
    Merchant findOne(Long merchantId) throws BizSilentException {

        AssertUtils.notNull(merchantId, ILLEGAL_PARAMETER, "Argument reqVo.id null.");

        Merchant merchant = merchantRepository.findOne(merchantId);
        AssertUtils.notNull(merchant, MERCHANT_NOT_FOUND, format("Merchant not found by id:%s", merchantId));

        return merchant;
    }

    public SpringPageVO<MerchantResVo> findAll(MerchantQueryVo queryVo) {

        PageRequest pageable = queryVo.toPageRequest();
        Page<Merchant> page = merchantRepository.findAll(pageable);
        return SpringPageToSpringPageVO.of(page, input -> CopyUtils.copyProperties(input, new MerchantResVo()));
    }

    @Transactional
    public MerchantResVo update(MerchantReqVo reqVo) {

        validateParams(reqVo);
        AssertUtils.notNull(reqVo.getId(), ILLEGAL_PARAMETER, "Argument id is null");
        AssertUtils.notNull(reqVo.getStatus(), ILLEGAL_PARAMETER, "Argument status is null");

        Merchant merchant = merchantRepository.findOne(reqVo.getId());
        AssertUtils.notNull(merchant, MERCHANT_NOT_FOUND, format("Merchant not found by id:'%s'", reqVo.getId()));
        BeanUtils.copyProperties(reqVo, merchant);
        Merchant savedMerchant = merchantRepository.save(merchant);
        return toMerchantResVo(savedMerchant);
    }

    /**
     * 事务提交成功之后才触发的事件监听器:@TransactionalEventListener
     */
    @TransactionalEventListener
    void listenNewCatEvent(NewMerchantEvent event) {
        log.info("listen event: {}", event);
    }

    private MerchantResVo toMerchantResVo(Merchant savedMerchant) {
        MerchantResVo merchantResVo = new MerchantResVo();
        BeanUtils.copyProperties(savedMerchant, merchantResVo);
        return merchantResVo;
    }


    private void validateParams(MerchantReqVo reqVo) {
        AssertUtils.notNull(reqVo, ILLEGAL_PARAMETER, "Argument reqVo is null");
        AssertUtils.hasText(reqVo.getName(), ILLEGAL_PARAMETER, "Name is blank");
    }


}
